const axios = require('axios');
const WebSocket = require('ws');

// 测试配置
const config = {
  baseUrl: 'http://localhost:3000',
  wsUrl: 'ws://localhost:3000/user-service/websocket',
  testUser: {
    mobile: `138${Date.now().toString().slice(-8)}`, // 生成唯一手机号
    password: '123456',
    channel: 'test',
    inviteCode: 'TEST001'
  }
};

// 全局变量
let authToken = '';
let userId = null;
let ws = null;
let testResults = {
  register: false,
  login: false,
  wsConnect: false,
  createCharacter: false,
  queryCharacters: false,
  selectCharacter: false,
  receiveLocationInfo: false,
  announcementTest: false,
  receivedMessages: []
};


console.log('🚀 开始运行前缘三国手游完整功能测试...');
console.log('='.repeat(60));

// 工具函数
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const logStep = (step, message) => {
  console.log(`\n📋 ${step}: ${message}`);
};

const logSuccess = (message) => {
  console.log(`✅ ${message}`);
};

const logError = (message) => {
  console.error(`❌ ${message}`);
};

const logInfo = (message) => {
  console.log(`ℹ️  ${message}`);
};

// 1. 用户注册测试
async function testRegister() {
  logStep('步骤1', '用户注册测试');

  try {
    const response = await axios.post(`${config.baseUrl}/user-service/user/register`, {
      mobile: config.testUser.mobile,
      pwd: config.testUser.password,
      captcha: '123456', // 使用默认验证码
      channel: config.testUser.channel,
      code: config.testUser.inviteCode
    });

    if (response.data.code === 0) {
      logSuccess('用户注册成功');
      testResults.register = true;
      return true;
    } else {
      logError(`注册失败: ${response.data.msg}`);
      return false;
    }
  } catch (error) {
    if (error.response?.data?.code === 4001 && error.response.data.msg.includes('已注册')) {
      logInfo('用户已存在，继续测试');
      testResults.register = true;
      return true;
    }
    logError(`注册异常: ${error.message}`);
    return false;
  }
}

// 2. 用户登录测试
async function testLogin() {
  logStep('步骤2', '用户登录测试');

  try {
    const response = await axios.post(`${config.baseUrl}/user-service/user/login`, {
      mobile: config.testUser.mobile,
      pwd: config.testUser.password
    });

    if (response.data.code === 0) {
      authToken = response.data.data.accessToken;
      userId = response.data.data.userId;
      logSuccess(`用户登录成功，用户ID: ${userId}`);
      testResults.login = true;
      return true;
    } else {
      logError(`登录失败: ${response.data.msg}`);
      return false;
    }
  } catch (error) {
    logError(`登录异常: ${error.message}`);
    return false;
  }
}

// 3. WebSocket连接测试
async function testWebSocketConnect() {
  logStep('步骤3', 'WebSocket连接测试');

  return new Promise((resolve) => {
    ws = new WebSocket(`${config.wsUrl}?t=${authToken}`);

    ws.on('open', () => {
      logSuccess('WebSocket连接建立成功');
      testResults.wsConnect = true;
      resolve(true);
    });

    ws.on('error', (error) => {
      logError(`WebSocket连接错误: ${error.message}`);
      resolve(false);
    });

    ws.on('close', (code, reason) => {
      logInfo(`WebSocket连接关闭: ${code} - ${reason}`);
    });

    // 设置超时
    setTimeout(() => {
      if (!testResults.wsConnect) {
        logError('WebSocket连接超时');
        resolve(false);
      }
    }, 5000);
  });
}

// 4. 创建角色测试
async function testCreateCharacter() {
  logStep('步骤4', '创建角色测试');

  return new Promise((resolve) => {
    if (!ws || !testResults.wsConnect) {
      logError('WebSocket未连接，无法创建角色');
      resolve(false);
      return;
    }

    const createMessage = {
      c: 390, // 创建角色指令
      d: {
        sex: 1, // 男性
        roleType: 1, // 武士
        headIndex: 2
      }
    };

    logInfo(`发送创建角色指令: ${JSON.stringify(createMessage)}`);
    ws.send(JSON.stringify(createMessage));

    // 监听创建角色响应
    const messageHandler = (data) => {
      try {
        // 正确处理WebSocket消息数据
        let rawData;
        if (data instanceof Buffer) {
          rawData = data.toString();
        } else if (data.data) {
          // 如果是MessageEvent，访问data属性
          rawData = data.data.toString();
        } else {
          rawData = data.toString();
        }

        logInfo(`收到原始数据: ${rawData}`);

        const message = JSON.parse(rawData);
        logInfo(`解析后的消息: ${JSON.stringify(message)}`);

        if (message.act_id === 390 && message.code === 0) {
          logSuccess(`角色创建成功，角色ID: ${message.data}`);
          testResults.createCharacter = true;
          ws.removeEventListener('message', messageHandler);
          resolve(true);
        } else if (message.act_id === 390 && message.code === -1) {
          logError(`角色创建失败: ${message.msg}`);
          ws.removeEventListener('message', messageHandler);
          resolve(false);
        }
      } catch (error) {
        logError(`解析消息失败: ${error.message}`);
        logError(`原始数据: ${data.toString()}`);
        logError(`数据类型: ${typeof data}, 构造函数: ${data.constructor.name}`);
        if (data.data) {
          logError(`MessageEvent.data: ${data.data}`);
        }
      }
    };

    ws.addEventListener('message', messageHandler);

    // 设置超时
    setTimeout(() => {
      if (!testResults.createCharacter) {
        logError('角色创建超时');
        ws.removeEventListener('message', messageHandler);
        resolve(false);
      }
    }, 10000);
  });
}

// 5. 查询角色列表测试
async function testQueryCharacters() {
  logStep('步骤5', '查询角色列表测试');

  return new Promise((resolve) => {
    if (!ws || !testResults.wsConnect) {
      logError('WebSocket未连接，无法查询角色');
      resolve(false);
      return;
    }

    const queryMessage = {
      c: 3, // 查询角色指令
      d: null
    };

    logInfo(`发送查询角色指令: ${JSON.stringify(queryMessage)}`);
    ws.send(JSON.stringify(queryMessage));

    // 监听查询角色响应
    const messageHandler = (data) => {
      try {
        // 正确处理WebSocket消息数据
        let rawData;
        if (data instanceof Buffer) {
          rawData = data.toString();
        } else if (data.data) {
          // 如果是MessageEvent，访问data属性
          rawData = data.data.toString();
        } else {
          rawData = data.toString();
        }

        logInfo(`收到原始数据: ${rawData}`);

        const message = JSON.parse(rawData);
        logInfo(`解析后的消息: ${JSON.stringify(message)}`);

        if (message.act_id === 3) {
          if (message.roleList && message.roleList.length > 0) {
            logSuccess(`查询角色成功，找到 ${message.roleList.length} 个角色`);
            message.roleList.forEach((char, index) => {
              logInfo(`角色${index + 1}: ID=${char.id}, 名称=${char.name}, 职业=${char.roleType}, 等级=${char.lvl}`);
            });
            testResults.queryCharacters = true;
            ws.removeEventListener('message', messageHandler);
            resolve(true);
          } else {
            logInfo('用户暂无角色');
            testResults.queryCharacters = true;
            ws.removeEventListener('message', messageHandler);
            resolve(true);
          }
        }
      } catch (error) {
        logError(`解析消息失败: ${error.message}`);
        logError(`原始数据: ${data.toString()}`);
        logError(`数据类型: ${typeof data}, 构造函数: ${data.constructor.name}`);
        if (data.data) {
          logError(`MessageEvent.data: ${data.data}`);
        }
      }
    };

    ws.addEventListener('message', messageHandler);

    // 设置超时
    setTimeout(() => {
      if (!testResults.queryCharacters) {
        logError('查询角色超时');
        ws.removeEventListener('messageHandler');
        resolve(false);
      }
    }, 10000);
  });
}

// 6. 选择角色测试
async function testSelectCharacter() {
  logStep('步骤6', '选择角色测试');

  return new Promise((resolve) => {
    if (!ws || !testResults.wsConnect) {
      logError('WebSocket未连接，无法选择角色');
      resolve(false);
      return;
    }

    // 先查询角色列表，获取第一个角色ID
    const queryMessage = {
      c: 3,
      d: null
    };

    logInfo(`发送查询角色指令: ${JSON.stringify(queryMessage)}`);
    ws.send(JSON.stringify(queryMessage));

    let queryResponseReceived = false;

    const messageHandler = (data) => {
      try {
        // 正确处理WebSocket消息数据
        let rawData;
        if (data instanceof Buffer) {
          rawData = data.toString();
        } else if (data.data) {
          // 如果是MessageEvent，访问data属性
          rawData = data.data.toString();
        } else {
          rawData = data.toString();
        }

        const message = JSON.parse(rawData);

        // 只处理查询角色的响应
        if (message.act_id === 3 && !queryResponseReceived) {
          queryResponseReceived = true;

          if (message.roleList && message.roleList.length > 0) {
            const characterId = message.roleList[0].id;
            logInfo(`找到角色，ID: ${characterId}，开始选择角色`);

            // 选择角色
            const selectMessage = {
              c: 4, // 选择角色指令
              d: {
                characterId: characterId
              }
            };

            logInfo(`发送选择角色指令: ${JSON.stringify(selectMessage)}`);
            ws.send(JSON.stringify(selectMessage));

            // 监听选择角色响应
            const selectHandler = (data) => {
              try {
                // 正确处理WebSocket消息数据
                let selectRawData;
                if (data instanceof Buffer) {
                  selectRawData = data.toString();
                } else if (data.data) {
                  // 如果是MessageEvent，访问data属性
                  selectRawData = data.data.toString();
                } else {
                  selectRawData = data.toString();
                }

                logInfo(`收到选择角色响应原始数据: ${selectRawData}`);

                const selectResponse = JSON.parse(selectRawData);
                logInfo(`选择角色响应解析后: ${JSON.stringify(selectResponse)}`);

                // 记录所有收到的消息到测试结果中
                testResults.receivedMessages.push(selectResponse);

                if (selectResponse.act_id === 4 && selectResponse.code === 0) {
                  logSuccess(`角色选择成功: ${selectResponse.data.name}`);
                  testResults.selectCharacter = true;
                  ws.removeEventListener('message', selectHandler);
                  resolve(true);
                } else if (selectResponse.act_id === 4 && selectResponse.code === -1) {
                  logError(`角色选择失败: ${selectResponse.msg}`);
                  ws.removeEventListener('message', selectHandler);
                  resolve(false);
                }
              } catch (error) {
                logError(`解析选择角色响应失败: ${error.message}`);
                logError(`原始数据: ${data.toString()}`);
                logError(`数据类型: ${typeof data}, 构造函数: ${data.constructor.name}`);
                if (data.data) {
                  logError(`MessageEvent.data: ${data.data}`);
                }
              }
            };

            ws.addEventListener('message', selectHandler);

            // 设置选择角色超时
            setTimeout(() => {
              if (!testResults.selectCharacter) {
                logError('角色选择超时');
                ws.removeEventListener('message', selectHandler);
                resolve(false);
              }
            }, 10000);

          } else {
            logInfo('用户暂无角色，跳过选择角色测试');
            testResults.selectCharacter = true;
            resolve(true);
          }

          // 移除查询角色的消息监听器
          ws.removeEventListener('message', messageHandler);
        }
      } catch (error) {
        logError(`解析查询角色响应失败: ${error.message}`);
        logError(`原始数据: ${data.toString()}`);
        logError(`数据类型: ${typeof data}, 构造函数: ${data.constructor.name}`);
        if (data.data) {
          logError(`MessageEvent.data: ${data.data}`);
        }
      }
    };

    ws.addEventListener('message', messageHandler);

    // 设置查询角色超时
    setTimeout(() => {
      if (!queryResponseReceived) {
        logError('查询角色超时');
        ws.removeEventListener('message', messageHandler);
        resolve(false);
      }
    }, 10000);
  });
}

// 7. 获取公告测试
async function testAnnouncements() {
  logStep('步骤7', '获取公告测试');

  return new Promise((resolve) => {
    if (!ws || !testResults.wsConnect) {
      logError('WebSocket未连接，无法获取公告');
      resolve(false);
      return;
    }

    const announcementMessage = {
      c: 90, // 获取公告指令
      d: {
        pageNum: 0
      }
    };

    logInfo(`发送获取公告指令: ${JSON.stringify(announcementMessage)}`);
    ws.send(JSON.stringify(announcementMessage));

    // 监听公告响应
    const messageHandler = (data) => {
      try {
        // 正确处理WebSocket消息数据
        let rawData;
        if (data instanceof Buffer) {
          rawData = data.toString();
        } else if (data.data) {
          // 如果是MessageEvent，访问data属性
          rawData = data.data.toString();
        } else {
          rawData = data.toString();
        }

        logInfo(`收到公告响应原始数据: ${rawData}`);

        const message = JSON.parse(rawData);
        logInfo(`公告响应解析后: ${JSON.stringify(message)}`);

        // 记录所有收到的消息到测试结果中
        testResults.receivedMessages.push(message);

        if (message.act_id === 90 && message.code === 0) {
          if (message.list && message.list.length > 0) {
            logSuccess(`✅ 获取公告成功，共 ${message.list.length} 条公告`);
            message.list.forEach((announcement, index) => {
              logInfo(`公告${index + 1}: ${announcement.title} (状态: ${announcement.state})`);
            });
          } else {
            logInfo('暂无公告数据');
          }
          testResults.announcementTest = true;
          ws.removeEventListener('message', messageHandler);
          resolve(true);
        } else if (message.act_id === 90 && message.code === -1) {
          logError(`获取公告失败: ${message.msg}`);
          ws.removeEventListener('message', messageHandler);
          resolve(false);
        }
      } catch (error) {
        logError(`解析公告响应失败: ${error.message}`);
        logError(`原始数据: ${data.toString()}`);
        logError(`数据类型: ${typeof data}, 构造函数: ${data.constructor.name}`);
        if (data.data) {
          logError(`MessageEvent.data: ${data.data}`);
        }
      }
    };

    ws.addEventListener('message', messageHandler);

    // 设置超时
    setTimeout(() => {
      if (!testResults.announcementTest) {
        logError('获取公告超时');
        ws.removeEventListener('message', messageHandler);
        resolve(false);
      }
    }, 10000);
  });
}

// 8. 接收被动消息测试
async function testReceivePassiveMessages() {
  logStep('步骤7', '接收被动消息测试');

  return new Promise((resolve) => {
    if (!ws || !testResults.wsConnect) {
      logError('WebSocket未连接，无法接收消息');
      resolve(false);
      return;
    }

    // 由于选择角色后已经收到了被动消息，我们直接检查测试结果
    // 这些消息已经在选择角色测试中被记录在 testResults.receivedMessages 中

    const expectedMessages = ['100', '200', '300', '120', '1425']; // 期望接收的消息类型
    const receivedTypes = new Set();

    // 检查已经收到的消息
    testResults.receivedMessages.forEach(msg => {
      if (msg.act_id) {
        const actId = msg.act_id.toString();
        if (expectedMessages.includes(actId)) {
          receivedTypes.add(actId);

          switch (actId) {
            case '100':
              logSuccess(`✅ 已收到区域信息: ${msg.name}`);
              break;
            case '200':
              logSuccess(`✅ 已收到NPC列表: ${msg.npclist?.length || 0} 个NPC`);
              break;
            case '300':
              logSuccess(`✅ 已收到角色状态: ${msg.name} (HP: ${msg.hp}/${msg.maxHp})`);
              break;
            case '120':
              logSuccess(`✅ 已收到区域状态: ${msg.state}`);
              break;
            case '1425':
              logSuccess(`✅ 已收到新手大礼包: ${msg.data?.[0]?.name || '未知'}`);
              break;
          }
        }
      }
    });

    // 检查是否收到了所有期望的消息
    if (receivedTypes.size === expectedMessages.length) {
      logSuccess('🎉 已收到所有期望的被动消息！');
      testResults.receiveLocationInfo = true;
      resolve(true);
    } else {
      logError(`接收被动消息不完整，已收到 ${receivedTypes.size}/${expectedMessages.length} 种类型`);
      logInfo(`已收到的消息类型: ${Array.from(receivedTypes).join(', ')}`);
      logInfo(`期望的消息类型: ${expectedMessages.join(', ')}`);
      resolve(false);
    }
  });
}

// 8. 生成测试报告
function generateTestReport() {
  console.log('\n' + '='.repeat(60));
  console.log('📊 测试报告');
  console.log('='.repeat(60));

  const totalTests = Object.keys(testResults).length;
  const passedTests = Object.values(testResults).filter(Boolean).length;
  const successRate = ((passedTests / totalTests) * 100).toFixed(1);

  console.log(`总测试项目: ${totalTests}`);
  console.log(`通过测试: ${passedTests}`);
  console.log(`失败测试: ${totalTests - passedTests}`);
  console.log(`成功率: ${successRate}%`);

  console.log('\n详细结果:');
  Object.entries(testResults).forEach(([test, result]) => {
    const status = result ? '✅ 通过' : '❌ 失败';
    const testName = {
      register: '用户注册',
      login: '用户登录',
      wsConnect: 'WebSocket连接',
      createCharacter: '创建角色',
      queryCharacters: '查询角色',
      selectCharacter: '选择角色',
      receiveLocationInfo: '接收被动消息',
      announcementTest: '获取公告'
    }[test] || test;

    console.log(`  ${testName}: ${status}`);
  });

  if (testResults.receivedMessages.length > 0) {
    console.log('\n接收到的消息统计:');
    const messageCounts = {};
    testResults.receivedMessages.forEach(msg => {
      if (msg.act_id) {
        messageCounts[msg.act_id] = (messageCounts[msg.act_id] || 0) + 1;
      }
    });

    Object.entries(messageCounts).forEach(([actId, count]) => {
      console.log(`  act_id ${actId}: ${count} 条`);
    });
  }

  console.log('\n' + '='.repeat(60));

  if (passedTests === totalTests) {
    console.log('🎉 所有测试通过！功能运行正常！');
  } else {
    console.log('⚠️  部分测试失败，请检查相关功能！');
  }
}

// 9. 清理资源
function cleanup() {
  if (ws) {
    ws.close();
  }
  console.log('\n🧹 测试完成，资源已清理');
}

// 10. 主测试流程
async function runAllTests() {
  try {
    // 执行所有测试步骤，有依赖性的步骤失败时立即终止

    // 步骤1: 用户注册 - 基础步骤，失败则终止
    const registerResult = await testRegister();
    if (!registerResult) {
      logError('🚨 用户注册失败，无法继续后续测试！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(1000);

    // 步骤2: 用户登录 - 关键步骤，失败则终止
    const loginResult = await testLogin();
    if (!loginResult) {
      logError('🚨 用户登录失败，无法继续后续测试！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(1000);

    // 步骤3: WebSocket连接 - 关键步骤，失败则终止
    const wsConnectResult = await testWebSocketConnect();
    if (!wsConnectResult) {
      logError('🚨 WebSocket连接失败，无法继续后续测试！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(1000);

    // 步骤4: 创建角色 - 可选步骤，失败不影响后续测试（可能角色已存在）
    const createCharacterResult = await testCreateCharacter();
    if (!createCharacterResult) {
      logInfo('⚠️  角色创建失败，但继续测试（可能角色已存在）');
    }
    await delay(2000);

    // 步骤5: 查询角色 - 关键步骤，失败则终止
    const queryCharactersResult = await testQueryCharacters();
    if (!queryCharactersResult) {
      logError('🚨 查询角色失败，无法继续后续测试！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(2000);

    // 步骤6: 选择角色 - 关键步骤，失败则终止
    const selectCharacterResult = await testSelectCharacter();
    if (!selectCharacterResult) {
      logError('🚨 选择角色失败，无法继续后续测试！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(2000);

    // 步骤7: 获取公告 - 核心功能验证，失败则终止
    const announcementResult = await testAnnouncements();
    if (!announcementResult) {
      logError('🚨 获取公告失败，核心功能验证失败！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(2000);

    // 步骤8: 接收被动消息 - 核心功能验证，失败则终止
    const receivePassiveMessagesResult = await testReceivePassiveMessages();
    if (!receivePassiveMessagesResult) {
      logError('🚨 接收被动消息失败，核心功能验证失败！');
      generateTestReport();
      cleanup();
      process.exit(1);
    }
    await delay(1000);

    // 所有测试都成功完成
    logSuccess('🎉 所有关键测试步骤都成功完成！');
    generateTestReport();

  } catch (error) {
    logError(`🚨 测试过程中发生严重错误: ${error.message}`);
    logError(`错误堆栈: ${error.stack}`);
    generateTestReport();
    cleanup();
    process.exit(1);
  } finally {
    // 等待一段时间后清理资源
    setTimeout(() => {
      cleanup();
      process.exit(0);
    }, 3000);
  }
}

// 11. 服务状态检查
async function checkServiceStatus() {
  logStep('预检查', '验证服务状态');

  try {
    // 检查HTTP服务
    const response = await axios.get(`${config.baseUrl}/`);
    if (response.data.status === 'ok') {
      logSuccess('HTTP服务正常运行');
    } else {
      logError('HTTP服务状态异常');
      return false;
    }

    // 检查端口是否被占用（通过尝试连接WebSocket）
    return new Promise((resolve) => {
      const testWs = new WebSocket(`${config.wsUrl}?t=test`);
      let resolved = false;

      const cleanup = () => {
        if (!resolved) {
          resolved = true;
          testWs.close();
        }
      };

      testWs.on('open', () => {
        logSuccess('WebSocket服务端口可用');
        cleanup();
        resolve(true);
      });

      testWs.on('error', (error) => {
        if (error.message.includes('ECONNREFUSED')) {
          logError('WebSocket服务未启动或端口不可用');
          cleanup();
          resolve(false);
        } else {
          logSuccess('WebSocket服务正常运行（认证失败是预期的）');
          cleanup();
          resolve(true);
        }
      });

      setTimeout(() => {
        if (!resolved) {
          logError('WebSocket服务检查超时');
          cleanup();
          resolve(false);
        }
      }, 5000);
    });

  } catch (error) {
    if (error.code === 'ECONNREFUSED') {
      logError('🚨 服务未启动！请先启动NestJS服务：');
      logError('   cd nestjs-app && npm run start:dev');
      return false;
    } else {
      logError(`服务检查失败: ${error.message}`);
      return false;
    }
  }
}

// 启动测试
console.log('测试配置:');
console.log(`  基础URL: ${config.baseUrl}`);
console.log(`  WebSocket URL: ${config.wsUrl}`);
console.log(`  测试用户: ${config.testUser.mobile}`);
console.log('='.repeat(60));

// 检查依赖
try {
  require('axios');
  require('ws');
} catch (error) {
  console.error('❌ 缺少必要的依赖包，请先安装:');
  console.error('npm install axios ws');
  process.exit(1);
}

// 运行预检查和测试
async function startTesting() {
  // 先检查服务状态
  const serviceOk = await checkServiceStatus();
  if (!serviceOk) {
    logError('🚨 服务状态检查失败，测试终止！');
    process.exit(1);
  }

  await delay(1000);

  // 运行主测试流程
  runAllTests();
}

startTesting(); 